import { reactive } from "vue";
import { AxiosPromise } from "axios";
import { findIndex } from "@/utils";
import { eachTree, filter, treeMap } from "@/utils/tree";
import { getBoolDictOptions, getDictOptions, getIntDictOptions } from "@/utils/dict";

import { FormSchema } from "@/types/form";
import { TableColumn } from "@/types/table";
import { DescriptionsSchema } from "@/types/descriptions";
import { ComponentOptions, ComponentProps } from "@/types/components";
import { DictTag } from "@/components/DictTag";

export type CrudSchema = Omit<TableColumn, "children"> & {
    isSearch?: boolean // 是否在查询显示
    search?: CrudSearchParams // 查询的详细配置
    isTable?: boolean // 是否在列表显示
    table?: CrudTableParams // 列表的详细配置
    isForm?: boolean // 是否在表单显示
    form?: CrudFormParams // 表单的详细配置
    isDetail?: boolean // 是否在详情显示
    detail?: CrudDescriptionsParams // 详情的详细配置
    children?: CrudSchema[]
    dictType?: string // 字典类型
    dictClass?: "string" | "number" | "boolean" // 字典数据类型 string | number | boolean
}

type CrudSearchParams = {
    // 是否显示在查询项
    show?: boolean
    // 接口
    api?: () => Promise<any>
    // 搜索字段
    field?: string
} & Omit<FormSchema, "field">

type CrudTableParams = {
    // 是否显示表头
    show?: boolean
    // 列宽配置
    width?: number | string
    // 列是否固定在左侧或者右侧
    fixed?: "left" | "right"
} & Omit<FormSchema, "field">
type CrudFormParams = {
    // 是否显示表单项
    show?: boolean
    // 接口
    api?: () => Promise<any>
} & Omit<FormSchema, "field">

type CrudDescriptionsParams = {
    // 是否显示表单项
    show?: boolean
} & Omit<DescriptionsSchema, "field">

interface AllSchemas {
    searchSchema: FormSchema[];
    tableColumns: TableColumn[];
    formSchema: FormSchema[];
    detailSchema: DescriptionsSchema[];
}

const { t } = useI18n();

// 过滤所有结构
export const useCrudSchemas = (
    crudSchema: CrudSchema[]
): {
    allSchemas: AllSchemas
} => {
    // 所有结构数据
    const allSchemas = reactive<AllSchemas>({
        searchSchema: [],
        tableColumns: [],
        formSchema: [],
        detailSchema: []
    });

    const searchSchema = filterSearchSchema(crudSchema, allSchemas);
    allSchemas.searchSchema = searchSchema || [];

    const tableColumns = filterTableSchema(crudSchema);
    allSchemas.tableColumns = tableColumns || [];

    const formSchema = filterFormSchema(crudSchema, allSchemas);
    allSchemas.formSchema = formSchema;

    const detailSchema = filterDescriptionsSchema(crudSchema);
    allSchemas.detailSchema = detailSchema;

    return {
        allSchemas
    };
};

// 过滤 Search 结构
const filterSearchSchema = (crudSchema: CrudSchema[], allSchemas: AllSchemas): FormSchema[] => {
    const searchSchema: FormSchema[] = [];

    // 获取字典列表队列
    const searchRequestTask: Array<() => Promise<void>> = [];
    eachTree(crudSchema, (schemaItem: CrudSchema) => {
        // 判断是否显示
        if (schemaItem?.isSearch || schemaItem.search?.show) {
            let component = schemaItem?.search?.component || "Input";
            const options: ComponentOptions[] = [];
            let comonentProps: ComponentProps = {};
            if (schemaItem.dictType) {
                const allOptions: ComponentOptions = { label: "全部", value: "" };
                options.push(allOptions);
                getDictOptions(schemaItem.dictType).forEach((dict) => {
                    options.push(dict);
                });
                comonentProps = {
                    options: options
                };
                if (!schemaItem.search?.component) component = "Select";
            }
            const searchSchemaItem = {
                // 默认为 input
                component: component,
                componentProps: comonentProps,
                ...schemaItem.search,
                field: schemaItem.field,
                label: schemaItem.search?.label || schemaItem.label
            };
            if (searchSchemaItem.api) {
                searchRequestTask.push(async () => {
                    const res = await (searchSchemaItem.api as () => AxiosPromise)();
                    if (res) {
                        const index = findIndex(allSchemas.searchSchema, (v: FormSchema) => {
                            return v.field === searchSchemaItem.field;
                        });
                        if (index !== -1) {
                            allSchemas.searchSchema[index]!.componentProps!.options = filterOptions(
                                res,
                                searchSchemaItem.componentProps.optionsAlias?.labelField
                            );
                        }
                    }
                });
            }
            // 删除不必要的字段
            delete searchSchemaItem.show;

            searchSchema.push(searchSchemaItem);
        }
    });
    for (const task of searchRequestTask) {
        task();
    }
    return searchSchema;
};

// 过滤 table 结构
const filterTableSchema = (crudSchema: CrudSchema[]): TableColumn[] => {
    const tableColumns = treeMap<CrudSchema>(crudSchema, {
        conversion: (schema: CrudSchema) => {
            if (schema?.isTable !== false && schema?.table?.show !== false) {
                // add by 芋艿：增加对 dict 字典数据的支持
                if (!schema.formatter && schema.dictType) {
                    schema.formatter = (_: Recordable, __: TableColumn, cellValue: any) => {
                        return h(DictTag, {
                            type: schema.dictType!, // ! 表示一定不为空
                            value: cellValue
                        });
                    };
                }
                return {
                    ...schema.table,
                    ...schema
                };
            }
        }
    });

    // 第一次过滤会有 undefined 所以需要二次过滤
    return filter<TableColumn>(tableColumns as TableColumn[], (data) => {
        if (data.children === void 0) {
            delete data.children;
        }
        return !!data.field;
    });
};

// 过滤 form 结构
const filterFormSchema = (crudSchema: CrudSchema[], allSchemas: AllSchemas): FormSchema[] => {
    const formSchema: FormSchema[] = [];

    // 获取字典列表队列
    const formRequestTask: Array<() => Promise<void>> = [];

    eachTree(crudSchema, (schemaItem: CrudSchema) => {
        // 判断是否显示
        if (schemaItem?.isForm !== false && schemaItem?.form?.show !== false) {
            let component = schemaItem?.form?.component || "Input";
            let defaultValue: any = "";
            if (schemaItem.form?.value) {
                defaultValue = schemaItem.form?.value;
            } else {
                if (component === "InputNumber") {
                    defaultValue = 0;
                }
            }
            let comonentProps: ComponentProps = {};
            if (schemaItem.dictType) {
                const options: ComponentOptions[] = [];
                if (schemaItem.dictClass && schemaItem.dictClass === "number") {
                    getIntDictOptions(schemaItem.dictType).forEach((dict) => {
                        options.push(dict);
                    });
                } else if (schemaItem.dictClass && schemaItem.dictClass === "boolean") {
                    getBoolDictOptions(schemaItem.dictType).forEach((dict) => {
                        options.push(dict);
                    });
                } else {
                    getDictOptions(schemaItem.dictType).forEach((dict) => {
                        options.push(dict);
                    });
                }
                comonentProps = {
                    options: options
                };
                if (!(schemaItem.form && schemaItem.form.component)) component = "Select";
            }
            const formSchemaItem = {
                // 默认为 input
                component: component,
                componentProps: comonentProps,
                value: defaultValue,
                ...schemaItem.form,
                field: schemaItem.field,
                label: schemaItem.form?.label || schemaItem.label
            };

            if (formSchemaItem.api) {
                formRequestTask.push(async () => {
                    const res = await (formSchemaItem.api as () => AxiosPromise)();
                    if (res) {
                        const index = findIndex(allSchemas.formSchema, (v: FormSchema) => {
                            return v.field === formSchemaItem.field;
                        });
                        if (index !== -1) {
                            allSchemas.formSchema[index]!.componentProps!.options = filterOptions(
                                res,
                                formSchemaItem.componentProps.optionsAlias?.labelField
                            );
                        }
                    }
                });
            }

            // 删除不必要的字段
            delete formSchemaItem.show;

            formSchema.push(formSchemaItem);
        }
    });

    for (const task of formRequestTask) {
        task();
    }
    return formSchema;
};

// 过滤 descriptions 结构
const filterDescriptionsSchema = (crudSchema: CrudSchema[]): DescriptionsSchema[] => {
    const descriptionsSchema: FormSchema[] = [];

    eachTree(crudSchema, (schemaItem: CrudSchema) => {
        // 判断是否显示
        if (schemaItem?.isDetail !== false && schemaItem.detail?.show !== false) {
            const descriptionsSchemaItem = {
                ...schemaItem.detail,
                field: schemaItem.field,
                label: schemaItem.detail?.label || schemaItem.label
            };
            if (schemaItem.dictType) {
                descriptionsSchemaItem.dictType = schemaItem.dictType;
            }
            if (schemaItem.detail?.dateFormat || schemaItem.formatter == "formatDate") {
                // 优先使用 detail 下的配置，如果没有默认为 YYYY-MM-DD HH:mm:ss
                descriptionsSchemaItem.dateFormat = schemaItem?.detail?.dateFormat
                    ? schemaItem?.detail?.dateFormat
                    : "YYYY-MM-DD HH:mm:ss";
            }

            // 删除不必要的字段
            delete descriptionsSchemaItem.show;

            descriptionsSchema.push(descriptionsSchemaItem);
        }
    });

    return descriptionsSchema;
};

// 给options添加国际化
const filterOptions = (options: Recordable, labelField?: string) => {
    return options?.map((v: Recordable) => {
        if (labelField) {
            v["labelField"] = t(v.labelField);
        } else {
            v["label"] = t(v.label);
        }
        return v;
    });
};
